<template>
  <el-form-item
    ref="formItem"
    :prop="prop"
    class="nb-form-item-wrapper"
    :class="[
    required !== undefined ? 'is-required' : '',
    inline ? 'inline-item' : 'inline-item-none',
    type === 'editor' ? 'editor-z-index' : ''
    ]">
    <div
      class="label-wrapper"
      v-if="label"
      :class="[required !== undefined ? 'is-required' : '']"
    >
      {{label}}
      <el-tooltip class="item" effect="dark" placement="top">
        <div slot="content" v-html="labelTips"></div>
        <nb-img width="14" v-if="labelTips" url="../../src/assets/image/icon-info.png" class=" el-icon-tips"></nb-img>
      </el-tooltip>
    </div>
    <div v-if="preview && !boxed" class="show-value">
      <template v-if="type === 'image'">
        <img width="100" :src="cloneValue"/>
      </template>
      <template v-else>
        <div v-if="cloneValue" v-html="cloneValue"></div>
        <div v-else style="color: #999">-</div>
      </template>
    </div>
    <div class="flex-wrapper" v-if="!preview && !boxed">
      <el-input
        :type="type"
        :disabled="disabled"
        :readonly="readonly"
        :placeholder="placeholder"
        v-model="cloneValue"
        :maxlength="max || maxs"
        @blur="blur"
        @focus="focus"
        @input="updateValue"
        v-if="!type || type === 'textarea' || type === 'password' || type === 'number'"
      >
        <template v-if="prepend" slot="prepend">{{prepend}}</template>
        <template v-if="append" slot="append">{{append}}</template>
      </el-input>
      <div
        v-if="type === 'click'"
        class="click-input"
        :class="{clickNone: disabled}"
        @click="inputClick"
      >
        <template v-if="cloneValue">
          <span style="color: #999" v-if="!cloneValue.length">{{placeholder}}</span>
          <el-tag size="small" v-for="item in cloneValue" :key="item.id">{{item.name}}</el-tag>
        </template>
        <template v-else>
          <span style="color: #999">{{placeholder}}</span>
        </template>
      </div>
      <el-select
        v-if="type === 'select'"
        v-model="cloneValue"
        :placeholder="placeholder || '请选择'"
        clearable
        :filterable="search"
        :disabled="disabled"
        :multiple="multiple"
        @change="updateValue"
      >
        <el-option
          v-for="item in options"
          :key="item[defaultKey.key || defaultKey.value]"
          :label="item[defaultKey.label]"
          :value="item[defaultKey.value]">
        </el-option>
      </el-select>

      <el-date-picker
        v-if="type === 'datetime' || type === 'date'"
        v-model="cloneValue"
        :type="type"
        :editable="true"
        :disabled="disabled"
        :placeholder="placeholder || '选择日期时间'"
        @change="updateValue"
        :value-format="valueFormat"
      >
      </el-date-picker>

      <el-checkbox-group
        v-if="type === 'checkbox'"
        v-model="cloneValue"
        :disabled="disabled"
        @change="updateValue"
      >
        <el-checkbox v-for="item in checkItem" :label="item[defaultKey.value]" :key="item[defaultKey.value]">{{item[defaultKey.label]}}</el-checkbox>
      </el-checkbox-group>

      <el-radio-group
        v-if="type === 'radio'"
        v-model="cloneValue"
        :disabled="disabled"
        @change="updateValue"
      >
        <el-radio v-for="item in checkItem" :label="item[defaultKey.value]" :key="item[defaultKey.value] + ''">
          {{item[defaultKey.label]}}
          <span type="text" v-if="item.slot" class="el-icon-info el-icon-tips" :title="item.slot"></span>
        </el-radio>
      </el-radio-group>

      <div
        class="editor-btn"
        v-if="type === 'editor'"
        @click.stop="openEditor"
      >
        {{cloneValue ? '修改富文本编辑器' : '打开富文本编辑器'}}
        <span v-if="cloneValue" class="el-icon-success" :class="{can : !disabled}"></span>
      </div>

      <div
        class="editor-btn"
        v-if="type === 'oneEditor'"
        @click.stop="openOneEditor"
      >
        {{cloneValue ? '修改富文本编辑器' : '打开富文本编辑器'}}
        <span v-if="cloneValue && cloneValue !== '<p><br></p>'" class="el-icon-success" :class="{can : !disabled}"></span>
      </div>

      <upload-img
        v-if="type === 'image'"
        :max="maxs"
        :name="name"
        v-model="cloneValue"
        @updateValue="updateValue"
        @imageValue="imageValue"
        :upload="upload"
        ref="formImg"
      ></upload-img>

      <upload-video
        v-if="type === 'video'"
        :maxSize="maxs"
        v-model="cloneValue"
        @updateValue="updateValue"
        ref="formVideo"
        :valueNum="valueNum"
        :fileType="fileType"
      ></upload-video>

<!--      <el-cascader-->
<!--        v-if="type === 'city'"-->
<!--        :options="cityOptions"-->
<!--        v-model="cloneValue"-->
<!--        @change="updateValue"-->
<!--      ></el-cascader>-->

      <nb-file
        v-if="type === 'file'"
        :name="name"
        v-model="cloneValue"
        :multiple="multiple"
        ref="files"
        :max="maxs"
        :accept="accept"
        @updateValue="updateValue"
      ></nb-file>
      <nb-oss
        v-if="type === 'oss' && showOss"
        :name="name"
        v-model="cloneValue"
        :multiple="multiple"
        ref="files"
        :customeType="customeType"
        @resetOss="resetOss"
      ></nb-oss>

      <slot name="in"></slot>
      <slot name="out"></slot>
      <transition name="error">
        <div v-if="showError && !cancelError" class="el-form-item__error">{{showError}}</div>
      </transition>
    </div>
    <slot name="box"></slot>
    <el-row class="tips" v-if="tips || max">
      <el-col class="tips-text" v-if="tips && !showError" :span="20">
        <el-tooltip class="item" effect="dark" :content="tips" placement="top">
          {{tips}}
        </el-tooltip>
      </el-col>
      <el-col class="value-num" v-if="max" :span="!tips ? 24 : 12">{{num}}/{{max}}</el-col>
    </el-row>

    <input v-if="type !== 'image' && type !== 'file' && type !== 'oss'" ref="ipt" hidden :name="name"/>
    <nb-editor
      v-if="type === 'editor'"
      ref="nbEditor"
      @save="saveEditor"
    ></nb-editor>
  </el-form-item>
</template>

<script>
  import {isPhone, isInteger, isMoney, isPassword, formatInput, isNine, isDecimal, isDouDecimal, isFtoN, isFourDecimal, isFtoHn, isDecimalFour, isToFn, isToTh, urlHeader, checkCard, checkCard2, checkCard3, checkCardTW, isEcpInteger, isTwDec, isTwHun, isPositiveInteger} from '@/common/utils'
  import UploadImg from './upload-img.vue'
  import UploadVideo from './upload-video.vue'
  import {Cascader} from 'element-ui'
  import NbFile from './nb-file'
  import NbOss from './nb-oss'
  import NbImg from '@/components/nb-img'

  /**
   * 输入组件
   * label：输入框前显示的字段
   * placeholder: 输入框内的placeholder
   * value: 输入框默认值 调用的时候v-model即可
   * name: input的name字段
   * tips: 输入框下提示文字
   * prop: 用于校验的字段
   * max：输入框内数字长度限制，存在该值会出现数字长度提示
   * maxs: 输入框内数字长度限制，不会出现数字长度提示
   * required：该输入框必填。可选择 ""、isPhone、isInteger、isMoney、isPassword、isCard，可附带错误提示信息如：required="isPhone:电话号格式错误"
   * disabled: 只显示文字
   * input: 校验输入类型（非必填）如：input="isPhone:电话号格式错误"
   *
   * type:
   * 控制输入类型 input  textarea number  password 常用类型
   * radio 单选  checkbox 多选  select 下拉选框
   * 时间日期选择器  包括选择日期  和 日期加时间
   * 富文本
   * 上传图片
   * 上传视频
   * 身份证类型 集成了校验身份证接口 自动校验
   */
  export default {
    data () {
      return {
        cloneValue: this.value,
        validatorStatus: false,
        check: false,
        cancelError: false,
        mostError: '',
        patterns: '',
        validatorType: this.required && this.required.split(':')[0],
        cityOptions: [],
        oldValue: '',
        showOss: true
      }
    },
    components: {
      UploadImg,
      UploadVideo,
      ElCascader: Cascader,
      NbFile,
      NbOss,
      NbImg
    },
    props: {
      label: String,
      labelTips: String,
      placeholder: String,
      value: [String, Number, Array, Date],
      name: String,
      tips: String,
      prepend: String,
      append: String,
      prop: {
        type: String,
        default: ''
      },
      max: [Number, String],
      maxs: [Number, String],
      type: {
        type: String,
        default: ''
      },
      required: String,
      disabled: Boolean,
      readonly: {
        type: Boolean,
        default: false
      },
      multiple: Boolean,
      resetNo: Boolean,
      inline: {
        type: Boolean,
        default: true
      },
      preview: Boolean,
      boxed: Boolean,
      input: String,
      options: {
        type: Array,
        default: () => []
      },
      checkItem: {
        type: Array,
        default: () => []
      },
      defaultKey: {
        type: Object,
        default: () => {
          return {
            label: 'label',
            value: 'value'
          }
        }
      },
      pattern: String,
      valueFormat: String,
      double: Boolean,
      documentType: [String, Number],
      upload: Boolean,
      fileType: {
        type: String,
        default: 'avi,mp4,wmv,mov,FLV'
      },
      valueNum: {
        type: String,
        default: '1'
      },
      accept: String,
      search: Boolean, // 下拉选择框 可搜索配置  true 可搜索  默认不可搜索
      customeType: {
        type: Boolean,
        default: false
      },
      checkNone: Boolean
    },
    watch: {
      /**
       * 观察父组件传递过来的value是否变化
       * 有变化时把最新值赋值给当前实例中的cloneValue
       * 因为当前实例初始化时会初始化data中的数据，将this.value赋值给cloneValue
       * 如果这个实例在当前页面中没有被销毁
       * 父组件参数变化时不会再执行data中的参数赋值动作，导致当前实例中的cloneValue不能得到更新
       */
      value (data) {
        this.cloneValue = data
        this.formatValue(data)
      }
    },
    methods: {
      updateValue (val) {
        val && this.formatValue(val)
        this.check = false
        this.mostError = ''
        this.cancelError && (this.cancelError = false)
        !this.validatorStatus && (this.validatorStatus = true)
        if (this.double) {
          this.$emit('change', val)
        } else {
          this.$emit('input', val)
        }
      },
      formatValue (value) {
        value = value || ''
        if (this.patterns.length) {
          value = formatInput[this.patterns[0]](value, this.patterns[1])
        }
        let input = this.$refs.ipt
        input && (input.value = value)
        return value
      },
      reset () {
        if (this.resetNo) return
        let _type = Object.prototype.toString.call(this.cloneValue)
        this.validatorStatus = false
        this.check = false
        switch (_type) {
          case '[object String]':
            this.cloneValue = ''
            break
          case '[object Date]':
            this.cloneValue = ''
            break
          case '[object Number]':
            this.cloneValue = ''
            break
          case '[object Array]':
            this.cloneValue = []
            break
        }
        if (this.type === 'editor') {
          this.$refs.formEditor.initHtml('')
        } else if (this.type === 'image') {
          this.$refs.formImg.resetImg()
        } else if (this.type === 'video') {
          this.$refs.formVideo.resetVideo()
        }
      },
      getVideo () {
        return this.$refs.formVideo.getName()
      },
      validator (type, value) {
        value = value === '<p><br></p>' ? '' : value
        value = Object.prototype.toString.call(value) === '[object Undefined]' ? '' : value
        value = Object.prototype.toString.call(value) === '[object Array]' ? value.length > 0 ? value : '' : value
        let typeArr = type ? type.split(':') : this.input ? this.input.split(':') : []
        let nullMessage = this.placeholder || this.prop || ''
        if (this.input && !value) return false
        switch (typeArr[0] || '') {
          case '':
            return value ? '' : typeArr[1] ? typeArr[1] : '请输入内容'
          case 'isPhone':
            return ((value.length >= 11) || this.check) && (isPhone(value) ? '' : !value ? '请输入手机号' : typeArr[1] || '手机号格式不正确')
          case 'isInteger':
            return isInteger(value) ? '' : typeArr[1] || '请输入整数'
          case 'isDecimal':
            return isDecimal(value) ? '' : typeArr[1] || '请输入两位或四位小数'
          case 'isDecimalFour':
            return isDecimalFour(value) ? '' : typeArr[1] || '请输入四位以内的小数'
          case 'isMoney':
            return isMoney(value) ? '' : typeArr[1] || '请输入正确的金额'
          case 'isPassword':
            return ((value.length >= 6) || this.check) && (isPassword(value) ? '' : !value ? typeArr[1] || `请输入${nullMessage}` : typeArr[1] || '密码格式不正确')
          case 'isCard':
            if (this.documentType === '2' || this.documentType === '99' || this.documentType === '3') {
              if (!checkCard2(this.cloneValue)) {
                return '只能输入数字、字母、汉字类型'
              }
            } else if (this.documentType === '1') {
              if (this.cloneValue.length !== 18) {
                this.mostError = '身份证件类型为18位'
                return
              }
              if (!checkCard(this.cloneValue)) {
                return '只能输入数字、字母类型'
              }
            } else if (this.documentType === '4') {
              if (!checkCard3(this.cloneValue)) {
                return '证件号码格式不正确'
              }
              if (this.cloneValue.length > 10) {
                return '证件号码格式不正确'
              }
            } else if (this.documentType === '5') {
              if (!checkCardTW(this.cloneValue)) {
                return '证件号码格式不正确'
              }
              if (this.cloneValue.length > 10) {
                return '证件号码格式不正确'
              }
            }
            this.validatorType = 'isCard'
            if (!value) return '请输入证件号'
            break
          case 'isNine':
            return isNine(value) ? '' : typeArr[1] || '请输入0-99的数字'
          case 'isDouDecimal':
            return isDouDecimal(value) ? '' : typeArr[1] || '请输入两位小数'
          case 'isFtoN':
            return isFtoN(value) ? '' : typeArr[1] || '请输入1-99的整数'
          case 'isFourDecimal':
            return isFourDecimal(value) ? '' : typeArr[1] || '最多输入四位小数'
          case 'isFtoHn':
            return isFtoHn(value) ? '' : typeArr[1] || '请输入1-999的整数'
          case 'isToFn':
            return isToFn(value) ? '' : typeArr[1] || '请输入1-9999的整数'
          case 'isToTh':
            return isToTh(value) ? '' : typeArr[1] || '请输入1-30的整数'
          case 'urlHeader':
            return urlHeader(value) ? '' : typeArr[1] || '跳转地址必须以http://或https:/开头！'
          case 'isEcpInteger':
            return isEcpInteger(value) ? '' : typeArr[1] || '请输入正整数'
          case 'isTwDec':
            return isTwDec(value) ? '' : typeArr[1] || '允许输入大于0且最多输入两位小数'
          case 'isTwHun':
            return isTwHun(value) ? '' : typeArr[1] || '请输入两位小数'
          case 'isPositiveInteger':
            return isPositiveInteger(value) ? '' : typeArr[1] || '输入数字，T后的第N个工作日起息'
        }
      },
      focus () {
        this.oldValue = this.cloneValue
      },
      blur () {
        (!this.cloneValue && (this.required === undefined)) && (this.cancelError = true)
        this.$emit('onBlur')
        if (this.validatorType === 'isCard') {
          if (this.oldValue === this.cloneValue) {
            return
          }
          if (!this.cloneValue) {
            this.mostError = '请输入证件号！'
            return
          }
          if (this.documentType === '2' || this.documentType === '99' || this.documentType === '3') {
            if (this.cloneValue.length < 8 || this.cloneValue.length > 20) {
              this.mostError = '护照或其他证件类型长度最少8位最多20位'
              return
            }
            if (!checkCard2(this.cloneValue)) {
              this.mostError = '只能输入数字、字母、汉字类型'
              return
            }
          } else if (this.documentType === '1') {
            if (this.cloneValue.length !== 18) {
              this.mostError = '证件类型为18位'
              return
            }
            if (!checkCard(this.cloneValue)) {
              this.mostError = '只能输入数字、字母类型'
              return
            }
          } else if (this.documentType === '4') {
            if (!checkCard3(this.cloneValue) || this.cloneValue.length !== 10) {
              this.mostError = '证件号码格式不正确'
              return
            }
          } else if (this.documentType === '5') {
            if (!checkCardTW(this.cloneValue) || this.cloneValue.length !== 10) {
              this.mostError = '证件号码格式不正确'
              return
            }
          }
          if (!this.documentType) return
          if (this.checkNone) return
          this.$store.dispatch('CHECK_CARD', {
            param: {
              documentType: this.documentType,
              documentNo: this.cloneValue
            }
          }).then(res => {
            if (!res.success) {
              this.mostError = res.msg
            } else {
              return ''
            }
          })
        }
      },
      checkValue () {
        this.validatorStatus = true
        this.check = true
        return this.showError
      },
      checkErrorValue () {
        return this.cloneValue && this.showError
      },
      inputClick () {
        if (this.disabled) return
        this.$emit('click')
      },
      openEditor () {
        this.$refs.nbEditor.show(this.cloneValue)
      },
      openOneEditor () {
        if (this.disabled) return
        this.$emit('oneEditor')
      },
      saveEditor (data) {
        this.updateValue(data)
      },
      fetchCity () {
        this.$store.dispatch('COMMON_AREA', {param: {}}).then(res => {
          if (res.success) {
            res.data.map(item => {
              if (item.level === 1) {
                this.cityOptions.push({
                  label: item.name,
                  value: item.id,
                  children: []
                })
              }
            })
            this.cityOptions.map(item => {
              res.data.map(items => {
                if (item.value === items.parentId) {
                  item.children.push({
                    label: items.name,
                    value: items.id
                  })
                }
              })
            })
          }
        })
      },
      imageValue (value) {
        this.$emit('fileData', value)
      },
      resetFile () {
        this.$refs.files.resetData()
      },
      getOss () {
        return this.$refs.files.returnData()
      },
      resetOss () {
        this.showOss = false
        this.$nextTick(() => {
          this.showOss = true
        })
      }
    },
    computed: {
      num () {
        return (this.cloneValue && this.cloneValue.length) || 0
      },
      showError () {
        return this.mostError || ((this.validatorStatus || this.check) && ((this.required !== undefined) || this.input) && this.validator(this.required, this.cloneValue))
      }
    },
    created () {
    },
    mounted () {
      if (this.type === 'city') {
        this.fetchCity()
      }
      this.patterns = this.pattern ? this.pattern.split('|') : []
      this.formatValue(this.value)
    }
  }
</script>

<style lang="scss" >
  .nb-form-item-wrapper{
    .editor-z-index{
      position: relative;
      z-index: 99;
    }
    .tips{
      font-size: 12px;
      line-height: 200%;
      position: relative;
    }
    .tips-text{
      position: absolute;
      left: 0;
      top: 0px;
      color: #999;
      font-size: 12px;
      font-weight: 200;
    }
      .value-num{
        text-align: right;
        position: absolute;
        right: 0;
        top: 0px;
      }
      .show-value{
        padding-left: 10px;
      }
      .flex-wrapper{
        display: flex;
        position: relative;
        line-height: 40px;
        .el-input{
          flex: 1;
        }
        .right-box{
          height: 38px;
          top: 1px;
          position: absolute;
          right: 1px;
          line-height: 38px;
          background: white;
          border-radius: 0 4px 4px 0;
          z-index: 20;
        }
        .out-box{
          padding: 0 15px;
        }
        .out-box.cursor{
          cursor: pointer;
        }
        .el-select,.wangEditor{
          width: 100%;
        }
        .el-radio-group{
          /*height: 40px;*/
          line-height: 50px !important;
        }
        .click-input{
          cursor: pointer;
          -webkit-appearance: none;
          background-color: #fff;
          background-image: none;
          border-radius: 4px;
          border: 1px solid #d8dce5;
          -webkit-box-sizing: border-box;
          box-sizing: border-box;
          color: #5a5e66;
          /*display: inline-block;*/
          font-size: inherit;
          min-height: 40px;
          line-height: 37px;
          outline: 0;
          padding: 0 15px;
          display: flex;
          flex-wrap: wrap;
          align-items: center;
          -webkit-transition: border-color .2s cubic-bezier(.645,.045,.355,1);
          transition: border-color .2s cubic-bezier(.645,.045,.355,1);
          width: 100%;
          .el-tag{
            margin: 5px 5px 5px 0;
          }
        }
        .click-input.clickNone{
          background-color: #f5f7fa;
          border-color: #dfe4ed;
          color: #b4bccc;
          cursor: not-allowed;
        }
        .editor-btn{
          display: block;
          padding: 0 10px;
          align-items: center;
          min-height: 40px;
          /*border: 1px solid red;*/
          border: 1px solid #f1f1f1;
          width: 100%;
          border-radius: 4px;
          line-height: 40px;

        }
        .el-checkbox-group,.el-radio-group{
          display: flex;
          flex-wrap: wrap;
          padding: 0 10px;
          align-items: center;
          min-height: 40px;
          /*border: 1px solid red;*/
          border: 1px solid #f1f1f1;
          width: 100%;
          border-radius: 4px;
          label{
            line-height: 25px;
            margin: 0 5px;
          }
        }
        .editor-btn{
          text-align: center;
          color: #409eff;
          cursor: pointer;
          .el-icon-success{
            float: right;
            position: relative;
            top: 13px;
          }
          .el-icon-success.can{
            color: rgb(24, 203, 154);
          }
        }
        .el-cascader{
          width: 100%;
        }
      }
    .el-form-item__error{
      height: 16px;
      overflow: hidden;
    }

    .error-enter,.error-leave-to{
      /*opacity: 0;*/
      height: 0;
    }
    .error-enter-active,.error-leave-active{
       transition: all 0.2s linear;
    }
    .el-form-item{
      /*width: 540px;*/
      /*flex: 0 0 540px;*/
      -webkit-box-sizing: border-box;
      -moz-box-sizing: border-box;
      box-sizing: border-box;
      padding: 0 20px;
    }

    .label-wrapper{
      position: relative;
      display: inline-block;
      /*vertical-align: middle;*/
      font-size: 14px;
      color: #999;
      /*line-height: 40px;*/
      padding: 0 12px 10px 4px;
      -webkit-box-sizing: border-box;
      box-sizing: border-box;
      .el-icon-tips{
        position: absolute;
        top: 0px;
        right: -7px;
        cursor: pointer;
      }
    }
    .label-wrapper.is-required:after{
      content: '*';
      color: #fa5555;
      margin-left: 0px;
      position: relative;
      top: 3px;
    }
  }
</style>
